/*-------------------<-- Start of Description-->---------------------\ | create SAS dataset &outdata using LENGTH statement for numeric vars| | that optimizes the variable to the fewest # of bytes needed to | | maintain the accuracy of the values contained in the variable; | |---------------------<-- End of Description-->----------------------| |--------------------------------------------------------------------| |------------<-- Start of Files or Arguments Needed-->---------------| | Arguments neede: | | indata : input dataset name; Required; | | outdata: Output dataset name; Required; | | Note: the output dataset name cannot be the same as input dataset; | |---------------<-- End of Files Arguments Needed-->-----------------| |--------------------------------------------------------------------| |------------------<-- Start of Files Created-->---------------------| | Example: | | data one ; | | format y x 11.6; | | x=1.111; y=2.222;output; | | x=11.1234; y=1.1;output; | | run; | | %resizen(one); %prcnt(one); %print(one); | | Usage: %resizen(indata, outdata); | \-------------------<-- End of Files Created-->---------------------*/ %macro resizen/parmbuff; /*--------------------------------------------\ | Copy Right: Duo Zhou; | | Created: 3-11-2002 9:42pm; | | Purpose: Minimize numeric variables length; | \--------------------------------------------*/ %local I sqzlength _VAR_NAMES_ _VAR_N_ _MAX_LEN_ _oriord_ indata outdata; %let inbuff=%qscan(&syspbuff,1,%str((),)); %let outbuff=%qscan(&syspbuff,2,%str((),)); %let linesize = %SYSFUNC(GETOPTION(linesize)); %if (%index(%quote(&syspbuff),%quote(=))) %then %do; %if (%index(%quote(&inbuff),%quote(=))) %then %do; %if (%index(%quote(%upcase(%sysfunc(compress(%quote(&inbuff))))),%quote(INDATA=))) %then %do; %let indata=%qscan(&inbuff,2,%str(=)); %if (%index(%quote(&outbuff),%quote(=))) %then %do; %if (not %index(%quote(%upcase(%sysfunc(compress(%quote(&outbuff))))),%quote(OUTDATA=))) %then %do; %put ==> Alert! Keyword parameter "%qscan(&outbuff,1,%str(=))" is not defined!; %end; %else %do; %let outdata=%qscan(&outbuff,2,%str(=)); %end; %end; %else %do; %let outdata=&outbuff; %end; %end; %else %if (%index(%quote(%upcase(%sysfunc(compress(%quote(&inbuff))))),%quote(OUTDATA=))) %then %do; %let outdata=%qscan(&inbuff,2,%str(=)); %if (%index(%quote(&outbuff),%quote(=))) %then %do; %if (not %index(%quote(%upcase(%sysfunc(compress(%quote(&outbuff))))),%quote(INDATA=))) %then %do; %put ==> Alert! Keyword parameter "%qscan(&outbuff,1,%str(=))" is not defined!; %end; %else %do; %let indata=%qscan(&outbuff,2,%str(=)); %end; %end; %else %do; %let indata=&outbuff; %end; %end; %else %put ==> Alert! Keyword parameter "%qscan(&inbuff,1,%str(=))" is not defined!; %end; %else %if (%index(%quote(&outbuff),%quote(=))) %then %do; %if (%index(%quote(%upcase(%sysfunc(compress(%quote(&outbuff))))),%quote(INDATA=))) %then %do; %let indata=%qscan(&outbuff,2,%str(=)); %let outdata=&inbuff; %end; %else %if (%index(%quote(%upcase(%sysfunc(compress(%quote(&outbuff))))),%quote(OUTDATA=))) %then %do; %let indata=&inbuff; %let outdata=%qscan(&outbuff,2,%str(=)); %end; %else %do; %put ==> Alert! Keyword parameter "%qscan(&outbuff,1,%str(=))" is not defined!; %end; %end; %end; %else %do; %let indata=&inbuff; %let outdata=&outbuff; %end; %if (%quote(&indata) eq) %then %do; %put ==> Alert! No input dataset is to be resized!; %goto L9999; %end; %if (%quote(&outdata) eq) %then %do; %let outdata=&indata; %end; %put *=================================================* ; %put | Beginning to resize numeric variables. | ; %put | Please be patient because this process may | ; %put | require a lot of execution time. | ; %put *=================================================* ; %let _VAR_N_ = 0 ; %if (%nobs(&&indata)>=1) %then %do; /*##########################################################*/ /* begin executable code */ /*##########################################################*/ proc contents data=&indata memtype=data noprint out=_cntnts_; run; proc sql noprint; select count(distinct name), max(length) into: _VAR_N_, :_MAX_LEN_ from _cntnts_ where type=1; select distinct name into: _VAR_NAMES_ separated by ", " from _cntnts_ where type=1; select name into : _oriord_ separated by ' ' from _cntnts_ order by varnum; quit; %let best=Best%sysfunc(trimn(%sysfunc(left(&_MAX_LEN_)))); /* in case there are NO numeric vars in dataset, */ /* stop further processing */ %if (%quote(&_VAR_N_) = %quote(0)) %then %do; %put *==================================* ; %put | ERROR from resizen: | ; %put | No numeric variables in dataset. | ; %put | Execution terminating forthwith. | ; %put *==================================* ; %goto L9999 ; %end ; /* create macro vars containing variable name */ /* process variables of numeric type only */ data _null_; set _cntnts_; if type = 1; var_no + 1; call symput( '_VAR_'||left( put( var_no, 5. )), name); run; /* Compute the minimum length and format for each numeric variable*/ proc sql noprint; select max(length(trim(left(put(&_VAR_1, &best..))))), max(length(trim(left(scan(put(&_VAR_1, &best..), 2, '.'))))) %if &_VAR_N_ > 1 %then %do; %do _I_=2 %to &_VAR_N_; , max(length(trim(left(put(&&_VAR_&_I_, &best..))))), max(length(trim(left(scan(put(&&_VAR_&_I_, &best..), 2, '.'))))) %end; %end; into: FMTL1, :FMTD1 %if &_VAR_N_ > 1 %then %do; %do _I_=2 %to &_VAR_N_; , :FMTL&_I_, :FMTD&_I_ %end; %end; from &indata; quit; /* initialize SQZLENTH global macro var */ %let SQZLENTH = LENGTH ; %let SQZFMT=FORMAT ; %do I = 1 %to &_VAR_N_ ; %if (%quote(&&FMTD&I) ne ) %then %do; %let SQZLENTH = &SQZLENTH %qtrim(%left(&&_VAR_&I)) %trim(%left(%_max(%eval(&&FMTL&I+&&FMTD&I) 3))); %let SQZFMT=&SQZFMT %qtrim(%left(&&_VAR_&I)) %trim(%left(%eval(&&FMTL&I+&&FMTD&I))).%trim(%left(&&FMTD&I)); %end; %else %do; %if (&&FMTL&I lt 3) %then %let SQZLENTH = &SQZLENTH %qtrim(%left( &&_VAR_&I )) %trim(%left(3)); %else %if (&&FMTL&I gt 8) %then %let SQZLENTH = &SQZLENTH %qtrim(%left( &&_VAR_&I )) %trim(%left(8)); %else %let SQZLENTH = &SQZLENTH %qtrim(%left( &&_VAR_&I )) %trim(%left(&&FMTL&I)); %let SQZFMT=&SQZFMT %qtrim(%left(&&_VAR_&I)) %trim(%left(&&FMTL&I)).; %end; %end; /* apply SQZLENTH to incoming data, create output dataset */ data &outdata; retain &_oriord_; &SQZLENTH; &SQZFMT; set &indata; run; proc datasets nolist ; delete _cntnts_ _tmp_; run; %end; %L9999: %mend resizen;